package com.lazy.book.common.listener;

import cn.dev33.satoken.exception.NotWebContextException;
import cn.dev33.satoken.stp.StpUtil;
import com.lazy.book.common.entity.LoginUser;
import com.lazy.book.common.utils.LoginUtils;
import com.mybatisflex.annotation.InsertListener;
import com.mybatisflex.annotation.SetListener;
import com.mybatisflex.annotation.UpdateListener;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
public class EntityChangeListener implements InsertListener, UpdateListener, SetListener {

  @Override
  public void onInsert(Object o) {
    setPropertyIfPresent(o, "createTime", LocalDateTime.now());
    setPropertyIfPresent(o, "updateTime", LocalDateTime.now());
    if (isNotLogin()) {
      return;
    }
    setPropertyIfPresent(o, "createId", StpUtil.getLoginIdAsLong());
    setPropertyIfPresent(o, "createBy", StpUtil.getLoginId().toString());
    setPropertyIfPresent(o, "updateId", StpUtil.getLoginIdAsLong());
    setPropertyIfPresent(o, "updateBy", StpUtil.getLoginId().toString());
    LoginUser loginUser = LoginUtils.getLoginUser();
    List<Long> deptOptions = loginUser.getDepts();
    if (deptOptions.isEmpty())
      return;
    setPropertyIfPresent(o, "deptScope", deptOptions);



  }

  @Override
  public void onUpdate(Object o) {
    setPropertyIfPresent(o, "updateTime", LocalDateTime.now());
    if (isNotLogin()) {
      return;
    }
    setPropertyIfPresent(o, "updateId", StpUtil.getLoginIdAsLong());
    setPropertyIfPresent(o, "updateBy", StpUtil.getLoginId().toString());
  }

  @Override
  public Object onSet(Object entity, String property, Object value) {
    return value;
  }

  private void setPropertyIfPresent(Object object, String propertyName, Object propertyValue) {
    try {
      Class<?> clazz = object.getClass();
      String setterName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
      Method setterMethod = null;

      // 遍历所有方法，寻找匹配的 setter
      for (Method method : clazz.getDeclaredMethods()) {
        if (method.getName().equals(setterName) && method.getParameterCount() == 1) {
          Class<?> parameterType = method.getParameterTypes()[0];
          if (parameterType.isAssignableFrom(propertyValue.getClass())) {
            setterMethod = method;
            break;
          }
        }
      }

      if (setterMethod != null) {
        setterMethod.invoke(object, propertyValue);
      } else {
        log.warn("Failed to set property '{}': Setter method not found or type mismatch.", propertyName);
      }
    } catch (IllegalAccessException | InvocationTargetException e) {
      log.warn(" Fill EntityChangeField failed; Error accessing property {}: {}", propertyName, e.getMessage());
    }
  }

  private boolean isNotLogin() {
    try {
      return !StpUtil.isLogin();
    } catch (NotWebContextException e) {
      // 处理非 Web 环境异常，返回未登录
      return true;
    } catch (Exception e) {
      // 记录所有其他异常，并返回未登录
      log.error("[EntityChangeListener] Unexpected error during login check: {}", e.getMessage(), e);
      return true;
    }
  }

}
